package com.demo.supplier.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demo.supplier.config.MinioProperties;
import com.demo.supplier.entity.FileInfo;
import com.demo.supplier.exception.BusinessException;
import com.demo.supplier.mapper.FileInfoMapper;
import com.demo.supplier.service.FileService;
import com.demo.supplier.utils.CommonUtil;
import com.demo.supplier.vo.FileInfoVo;
import com.demo.supplier.vo.FileUploadVo;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 文件服务实现类
 * 
 * @author demo
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioProperties minioProperties;

    @Autowired
    private FileInfoMapper fileInfoMapper;

    // 允许上传的图片格式
    private static final List<String> ALLOWED_IMAGE_TYPES = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp");

    // 最大文件大小：5MB
    private static final long MAX_FILE_SIZE = 5 * 1024 * 1024;

    @Override
    public String uploadFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException("文件不能为空");
        }

        // 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new BusinessException("文件大小不能超过5MB");
        }

        // 检查文件类型
        String originalFilename = file.getOriginalFilename();
        String fileExtension = CommonUtil.getFileExtension(originalFilename);
        if (!ALLOWED_IMAGE_TYPES.contains(fileExtension)) {
            throw new BusinessException("只支持jpg、jpeg、png、gif、bmp格式的图片");
        }

        try {
            // 确保存储桶存在
            ensureBucketExists();

            // 生成新的文件名
            String fileName = CommonUtil.generateFileName(originalFilename);

            // 获取文件输入流并确保关闭
            try (InputStream inputStream = file.getInputStream()) {
                // 上传文件
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(minioProperties.getBucketName())
                                .object(fileName)
                                .stream(inputStream, file.getSize(), -1)
                                .contentType(file.getContentType())
                                .build()
                );
            }

            // 返回文件访问URL
            return getFileUrl(fileName);

        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new BusinessException("文件上传失败：" + e.getMessage());
        }
    }

    @Override
    public void deleteFile(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return;
        }

        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(minioProperties.getBucketName())
                            .object(fileName)
                            .build()
            );
        } catch (Exception e) {
            log.error("删除文件失败：{}", fileName, e);
            throw new BusinessException("删除文件失败：" + e.getMessage());
        }
    }

    @Override
    public String getFileUrl(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return null;
        }

        try {
            return minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(minioProperties.getBucketName())
                            .object(fileName)
                            .expiry(7, TimeUnit.DAYS) // 7天有效期
                            .build()
            );
        } catch (Exception e) {
            log.error("获取文件URL失败：{}", fileName, e);
            return null;
        }
    }

    /**
     * 确保存储桶存在
     */
    private void ensureBucketExists() {
        try {
            boolean exists = minioClient.bucketExists(
                    BucketExistsArgs.builder()
                            .bucket(minioProperties.getBucketName())
                            .build()
            );

            if (!exists) {
                minioClient.makeBucket(
                        MakeBucketArgs.builder()
                                .bucket(minioProperties.getBucketName())
                                .build()
                );
            }
        } catch (Exception e) {
            log.error("检查/创建存储桶失败", e);
            throw new BusinessException("存储服务不可用");
        }
    }

    // =========================== 新增的数据库相关方法 ===========================

    @Override
    public FileUploadVo uploadFileWithDb(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException("文件不能为空");
        }

        // 检查文件大小
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new BusinessException("文件大小不能超过5MB");
        }

        // 检查文件类型
        String originalFilename = file.getOriginalFilename();
        String fileExtension = CommonUtil.getFileExtension(originalFilename);
        if (!ALLOWED_IMAGE_TYPES.contains(fileExtension.toLowerCase())) {
            throw new BusinessException("只支持jpg、jpeg、png、gif、bmp格式的图片");
        }

        try {
            // 计算文件MD5（单独的输入流，使用后立即关闭）
            String fileMd5;
            try (InputStream md5Stream = file.getInputStream()) {
                fileMd5 = DigestUtil.md5Hex(md5Stream);
            }
            
            // 检查是否已存在相同文件
            LambdaQueryWrapper<FileInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FileInfo::getFileMd5, fileMd5)
                    .eq(FileInfo::getStatus, 1)
                    .eq(FileInfo::getDeleted, 0);
            FileInfo existingFile = fileInfoMapper.selectOne(queryWrapper);
            
            if (existingFile != null) {
                // 返回已存在的文件信息
                return buildFileUploadVo(existingFile);
            }

            // 确保存储桶存在
            ensureBucketExists();

            // 生成新的文件名
            String storageName = CommonUtil.generateFileName(originalFilename);

            // 获取文件输入流并上传到MinIO（确保关闭）
            try (InputStream inputStream = file.getInputStream()) {
                minioClient.putObject(
                        PutObjectArgs.builder()
                                .bucket(minioProperties.getBucketName())
                                .object(storageName)
                                .stream(inputStream, file.getSize(), -1)
                                .contentType(file.getContentType())
                                .build()
                );
            }
            
            // 保存文件信息到数据库
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(originalFilename);
            fileInfo.setStorageName(storageName);
            fileInfo.setFilePath(storageName);
            fileInfo.setFileType(fileExtension.toLowerCase());
            fileInfo.setFileSize(file.getSize());
            fileInfo.setContentType(file.getContentType());
            fileInfo.setFileMd5(fileMd5);
            fileInfo.setStatus(1);
            
            fileInfoMapper.insert(fileInfo);
            
            // 获取文件访问URL
            String accessUrl = getFileUrl(storageName);
            return buildFileUploadVo(fileInfo, accessUrl);

        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new BusinessException("文件上传失败：" + e.getMessage());
        }
    }

    @Override
    public List<FileUploadVo> uploadFiles(List<MultipartFile> files) {
        if (files == null || files.isEmpty()) {
            throw new BusinessException("文件列表不能为空");
        }

        List<FileUploadVo> results = new ArrayList<>();
        for (MultipartFile file : files) {
            try {
                FileUploadVo result = uploadFileWithDb(file);
                results.add(result);
            } catch (Exception e) {
                log.error("批量上传中的文件 {} 上传失败", file.getOriginalFilename(), e);
            }
        }
        
        return results;
    }

    @Override
    public void deleteFileById(Long fileId) {
        if (fileId == null) {
            throw new BusinessException("文件ID不能为空");
        }

        FileInfo fileInfo = fileInfoMapper.selectById(fileId);
        if (fileInfo == null) {
            throw new BusinessException("文件不存在");
        }

        // 检查文件是否被使用
        if (isFileInUse(fileId)) {
            throw new BusinessException("文件正在被使用，无法删除");
        }

        // 逻辑删除文件记录
        fileInfo.setStatus(0);
        fileInfo.setDeleted(1);
        fileInfoMapper.updateById(fileInfo);

        // 删除MinIO中的文件
        try {
            deleteFile(fileInfo.getStorageName());
        } catch (Exception e) {
            log.error("删除MinIO文件失败：{}", fileInfo.getStorageName(), e);
        }
    }

    @Override
    public String getFileUrlById(Long fileId) {
        if (fileId == null) {
            return null;
        }

        FileInfo fileInfo = fileInfoMapper.selectById(fileId);
        if (fileInfo == null || fileInfo.getDeleted() == 1 || fileInfo.getStatus() != 1) {
            return null;
        }

        return getFileUrl(fileInfo.getStorageName());
    }

    @Override
    public FileInfoVo getFileInfo(Long fileId) {
        if (fileId == null) {
            throw new BusinessException("文件ID不能为空");
        }

        FileInfo fileInfo = fileInfoMapper.selectById(fileId);
        if (fileInfo == null || fileInfo.getDeleted() == 1) {
            throw new BusinessException("文件不存在");
        }

        FileInfoVo vo = new FileInfoVo();
        vo.setFileId(fileInfo.getId());
        vo.setFileName(fileInfo.getFileName());
        vo.setFileSize(fileInfo.getFileSize());
        vo.setFileType(fileInfo.getFileType());
        vo.setAccessUrl(getFileUrl(fileInfo.getStorageName()));
        vo.setCreateTime(fileInfo.getCreateTime());

        return vo;
    }

    @Override
    public List<FileInfo> getFilesByIds(List<Long> fileIds) {
        if (fileIds == null || fileIds.isEmpty()) {
            return new ArrayList<>();
        }

        return fileInfoMapper.selectByIds(fileIds);
    }

    @Override
    public boolean isFileInUse(Long fileId) {
        if (fileId == null) {
            return false;
        }

        int usageCount = fileInfoMapper.checkFileUsage(fileId);
        return usageCount > 0;
    }

    /**
     * 构建文件上传响应VO
     */
    private FileUploadVo buildFileUploadVo(FileInfo fileInfo) {
        String accessUrl = getFileUrl(fileInfo.getStorageName());
        return buildFileUploadVo(fileInfo, accessUrl);
    }

    /**
     * 构建文件上传响应VO
     */
    private FileUploadVo buildFileUploadVo(FileInfo fileInfo, String accessUrl) {
        FileUploadVo vo = new FileUploadVo();
        vo.setFileId(fileInfo.getId());
        vo.setFileName(fileInfo.getFileName());
        vo.setFileSize(fileInfo.getFileSize());
        vo.setFileType(fileInfo.getFileType());
        vo.setAccessUrl(accessUrl);
        vo.setUploadTime(fileInfo.getCreateTime() != null ? fileInfo.getCreateTime() : LocalDateTime.now());
        return vo;
    }
}